
// Copyright (C) 2011-2012 Luca Piccioni
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//  
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//  
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;

namespace Derm.Scene
{
	/// <summary>
	/// Directed graph node.
	/// </summary>
	public class DirectedGraphNode<T> : IDirectedGraphNode<T> where T : DirectedGraphNode<T>
	{	
		#region IDirectedGraphNode Implementation

		/// <summary>
		/// Collection of IDirectedGraphNode linking to this IDirectedGraphNode.
		/// </summary>
		public T Parent { get { return (mParent); } }

		/// <summary>
		/// Number of links starting from this IDirectedGraphNode.
		/// </summary>
		public uint LinkCount { get { return ((uint)mChildren.Count); } }

		/// <summary>
		/// Create a link between this IDirectedGraphNode and another IDirectedGraphNode.
		/// </summary>
		/// <param name="node">
		/// Node to link as child of this DirectedGraphNode.
		/// </param>
		public void Link(T node)
		{
			node.mParent = (T) this;
			mChildren.Add(node);
		}

		/// <summary>
		/// Create a link between this IDirectedGraphNode and another IDirectedGraphNode.
		/// </summary>
		/// <param name="nodes">
		/// Enumerable of nodes to link as children of this DirectedGraphNode.
		/// </param>
		public void Link(IEnumerable<T> nodes)
		{
			if (nodes == null)
				throw new ArgumentNullException("nodes");

			foreach (T node in nodes)
				node.mParent = (T) this;

			mChildren.AddRange(nodes);
		}

		/// <summary>
		/// Delete the link between this DirectedGraphNode and another DirectedGraphNode.
		/// </summary>
		/// <param name="node">Node to unlink src child of this DirectedGraphNode.</param>
		public void Unlink(T node)
		{
			if (node == null)
				throw new ArgumentNullException("node");

			if (mChildren.Remove(node) == false)
				throw new InvalidOperationException("not in list");
			node.mParent = null;
		}

		/// <summary>
		/// Enumeration of IDirectedGraphNode linking by this IDirectedGraphNode.
		/// </summary>
		public IEnumerable<T> Children { get { return (mChildren); } }

		/// <summary>
		/// The parent list.
		/// </summary>
		private T mParent;

		/// <summary>
		/// The parent list.
		/// </summary>
		private readonly List<T> mChildren = new List<T>();

		#endregion
	}
}